/**
 * @file Image.c
 * @brief Fichier d'implémentation du module Image.
 *
 * 
 */

#include "Image.h"
#include "Pixel.h"



/* ********************************************************************* */
/*                                                                       */
/*                 Fonctions relatives aux images                        */
/*                                                                       */
/* ********************************************************************* */
void imInit ( Image *im, const int dimx, const int dimy)
{
        assert(im != NULL) ;
        assert(dimx > 0) ;
        assert(dimy > 0) ;

        im->dimx = dimx ;
        im->dimy = dimy ;
        im->pix = (Pixel *) malloc(dimx*dimy*sizeof(Pixel)) ;
}

void imLibere (Image *im)
{
    assert(im != NULL) ;
    assert(im->pix != NULL) ;

    im->dimx = 0 ;
    im->dimy = 0 ;
    free(im->pix);
    im->pix = NULL ;

}

Image * imCreer(const int dimx, const int dimy)
{
    Image *pIm ;
    pIm = (Image *) malloc(sizeof(Image)) ;
    imInit( pIm, dimx, dimy) ;

    return pIm ;
}

void imDetruire(Image *im)
{
    assert(im != NULL);

    imLibere(im);
    free(im);
    im = NULL ;
}

/* ********************************************************************* */
/*                                                                       */
/*           Accesseurs et Mutateurs de la structure Image               */
/*                                                                       */
/* ********************************************************************* */

Pixel getPix(const Image *im, const int x, const int y)
{

    assert(im != NULL) ;
    assert(x < im->dimx) ;
    assert(y < im->dimy) ;

    return im->pix[y*im->dimx+x] ;
}

void setPix(Image * im, const int x, const int y, const Pixel * couleur)
{

    assert(im != NULL) ;
    assert(x < im->dimx) ;
    assert(y < im->dimy) ;

    im->pix[y*im->dimx+x] = (*couleur) ;


}

/* ********************************************************************* */
/*                                                                       */
/*                 Fonctions relatives aux rectangles                    */
/*                                                                       */
/* ********************************************************************* */

void imDessineRectangle(Image *im, const int Xmin, const int Ymin, const int Xmax, const int Ymax, const Pixel * couleur)
{
    int i, j ;
    assert(im != NULL) ;
    assert(Xmin <= im->dimx) ;
    assert(Xmin >=0) ;
    assert(Ymin <= im->dimy) ;
    assert(Ymin >=0) ;
    assert(Xmax <= im->dimx) ;
    assert(Xmax >= Xmin) ;
    assert(Ymax <= im->dimy) ;
    assert(Ymax >= Ymin) ;

    for(i=Xmin ; i<Xmax ; i++){
        for(j=Ymin ; j<Ymax ; j++){
            setPix(im, i, j, couleur) ;
        }
    }
}

void imEffacer(Image *im, const Pixel * couleur)
{

    int Xmin = 0 ;
    int Ymin = 0 ;
    int Xmax = im->dimx ;
    int Ymax = im->dimy ;

    assert(im != NULL) ;

    imDessineRectangle(im, Xmin, Ymin, Xmax, Ymax, couleur) ;
}

/* ********************************************************************* */
/*                                                                       */
/*             Fonctions relatives aux gestiond'images                   */
/*                                                                       */
/* ********************************************************************* */

void imSauver(const Image *pIm, const char filename[])
{
    FILE* f;
	Pixel pix;
	int x,y;

    f = fopen(filename, "w");
    if (f==NULL)
    {
        printf("Erreur lors de l'ouverture de %s\n", filename);
        assert( f );
    }
    fprintf( f , "P3\n");                           /* P3 = ascii avec 3 composantes RVB */
    fprintf( f , "%d %d\n", pIm->dimx, pIm->dimy);      /* dimension de l'image */
    fprintf( f , "255\n");                          /* chaque composante est comprise entre 0 et 255*/

    for(y=0;y<pIm->dimy;++y)
        for(x=0;x<pIm->dimx;++x)
        {
            pix = getPix(pIm,x,y);
            fprintf(f, "%d %d %d  ", pix.r, pix.v, pix.b);
        }
    printf("Sauvegarde de l'image %s ...OK\n", filename);
    fclose(f);
}

void imOuvrir(Image *pIm, const char filename[])
{
    FILE* f;
	Pixel pix;
	int x, y, dimx, dimy;

    f = fopen(filename, "r");
    if (f==NULL)
    {
        printf("Erreur lors de l'ouverture de %s\n", filename);
        assert( f );
    }

    assert( fscanf( f , "P3\n%d %d\n255\n", &dimx, &dimy) ==2 );
    imInit( pIm, dimx, dimy);

    for(y=0;y<pIm->dimy;++y)
        for(x=0;x<pIm->dimx;++x)
        {
            assert( fscanf(f, "%d %d %d  ", &pix.r, &pix.v, &pix.b)==3 );
			setPix(pIm,x,y,&pix);
        }
    fclose(f);
    printf("Lecture de l'image %s ...OK\n", filename);
}

void imPrintf(const Image *pIm)
{
	int x,y;
	Pixel pix;

    printf( "%d %d\n", pIm->dimx, pIm->dimy);      /* dimension de l'image */

    for(y=0;y<pIm->dimy;++y)
    {
        for(x=0;x<pIm->dimx;++x)
        {
            pix = getPix(pIm,x,y);
            printf("%d %d %d  ", pix.r, pix.v, pix.b);
        }
        printf("\n");
    }
}

/* ********************************************************************* */
/*                                                                       */
/*                           Test de regression                          */
/*                                                                       */
/* ********************************************************************* */

void ImRegressionTest(void)
{
        Image im ;
	Image *im2;

	Image **im3;
	int i ;
	Pixel pix = {255, 255, 255};

	printf("TEST DE REGRESSION DU MODULE IMAGE : \n") ;

	/* Test de la fonction imInit */

	printf("\nTest de imInit pour une image de petite taille : ");
        imInit(& im, 1, 1 ) ;
        printf("ok.\n") ;

        printf("Test des accesseurs : ");
        assert(((im.dimx) == 1) && ((im.dimy) == 1) && (im.pix != NULL)) ;
        printf("ok.\n") ;

	imLibere(&im);

        printf("Test de imInit pour une image de taille moyenne : ");
        imInit(& im, 50, 50 ) ;
        printf("ok.\n") ;

        printf("Test des accesseurs : ");
	
        assert(((im.dimx) == 50) && ((im.dimy) == 50) && (im.pix != NULL)) ;
	
        printf("ok.\n") ;

	imLibere(&im);
	
        printf("Test de imInit pour une image de grande taille : ");
        imInit(& im, 4096, 4096 ) ;
        printf("ok.\n") ;

        printf("Test des accesseurs : ");
        assert(((im.dimx) == 4096) && ((im.dimy) == 4096) && (im.pix != NULL)) ;
        printf("ok.\n") ;
        
	/* Test de la fonction imlibere */
	
       	printf("\nAffichage des dimenssions de l'image avant libération: \n");
	printf("dimx est égale à : %d\n",im.dimx) ;
	printf("dimY est égale à : %d\n",im.dimy) ;

	printf("\nTest de la fonction imLibere : ");
	imLibere(& im) ;
	assert((im.dimx == 0) && (im.dimy == 0) && (im.pix == NULL)) ;
        printf("ok.\n") ;
	
	printf("\nAffichage des dimenssions de l'image après libération: \n");
	printf("dimx est égale à : %d\n",im.dimx) ;
	printf("dimY est égale à : %d\n",im.dimy) ;
	
	/* Test de la fonction imCreer */
	
	printf("\nTest de la fonction imCreer : ") ;
	im2 = imCreer(50,50) ;
	assert((im2 != NULL) && (im2->dimx == 50) && (im2->dimy == 50)) ;
	printf("ok. \n") ;

	printf("dimx : %d\n", im2->dimx) ;
	printf("dimy : %d\n", im2->dimy) ;
	
	/* Test de la fonction imDetruire */
	
	printf("\nTest de la fonction imDetruire : ") ;

	imDetruire(im2) ;

	printf("ok.\n") ;

	/* Traitement sur 100 images */
	printf("création d'un tableau contenant 100 images :\n") ;
	printf("Allocation d'un tableaux pour contenir les images : ") ;
	im3 = (Image **) malloc ( 100 * sizeof(Image *));
	printf("ok.\n") ;
	printf("Création des images : ") ;
	for(i = 0; i < 100; i++)
	  im3[i] = imCreer(i+100, i+512);
	printf("ok.\n") ;
	printf("Remplissage des images avec un pixel de couleur: ") ;
	for(i = 0; i < 100; i++)
	  imEffacer(im3[i], &pix);
	printf("ok.\n") ;
	printf("Suppression des images : ") ;
	for(i = 0; i < 100; i++)
	  imDetruire(im3[i]);
	printf("ok.\n") ;
	printf("Libération du tableau d'image : ") ;
	free(im3);
	printf("ok.\n") ;
        printf("\nTEST DE REGRESSION DU MODULE IMAGE") ;
}
